package gamecontrol;

import gameinfo.Level;
import gameobjects.*;
import java.util.Vector;
import utils.*;

/**
 * Saves the current values of the level that the user is playing. Too has methods
 * for managing this values. 
 * @author quique
 */
public class CurrentBoard implements ITimer{
        
        /**
         * Used for controling options like, the next level, scores, lifes, etc. 
         */
        private Game game;
        
        /**
         * User for moving the hero and other options
         */
        private Hero hero;
                
        /**
         * The time that the player has to pass the level. 
         */
	private int remainingTime;
	
        /**
         * Help that is showed when a new level starts.
         */
	private String help;
	
        /**
         * All the boxes that the current board has. 
         */
	private CollectionOfBoxes boxes;
        
        /**
         * Number of remaining beers to open the door, when there is no beers in the board
         */
	private int remainingBeers = 0;
        
        /**
         * Timer that has the power to control the interval times of the game.
         */
        protected Timer timer;
        
        /**
         * A vector for the control what boxes have been updated and what no. It
         * is used for not updating a box two or more times while all the boxes
         * had been updated. So, all the boxes must be updated before ones is
         * updated again. Too it save the elements that is nomoving in the board
         * like walls, exit, dirty terrain...
         */
	private Vector updatedBoxes;
        
        /**
         * Saves the x coordenate of the exit
         */
        private int xExit;
        
        /**
         * Saves the y coordenate of the exit
         */
        private int yExit;
	
        /**
         * Contructor. 
         * @param game
         */
        public CurrentBoard(Game game, Level level){
            this.game = game;
            setHelp(level.getInitialHelp());
            this.timer = new Timer();
            initializeRemainingTime(level.getInitialTime());
            //setup the boxes with the elements
            boxes = new CollectionOfBoxes(level.getXDimension(),level.getYDimension());
            for(int i=1;i<=level.getXDimension();i++){
                for (int j=1;j<=level.getYDimension();j++){
                    Box b = new Box();
                    b.setPosition(i, j);
                    //study what kind of element are
                    boolean found = false;//variable created for save time to processing
                    if(((String)level.getElement(i, j)).compareTo("Hero")==0){
                        b.setElement(new Hero());
                        b.getElement().setId(Element.HeroId);
                        b.getElement().setPriority(Element.HeroPriority);
                        this.hero = (Hero)b.getElement();
                        this.hero.setCurrentBoard(this);
                        found = true;
                    }
                    if(!found&&((String)level.getElement(i, j)).compareTo("IndestructibleWall")==0){
                        b.setElement(new Wall());
                        b.getElement().setId(Element.WallId);
                        b.getElement().setPriority(Element.WallPriority);
                        ((Wall)b.getElement()).setDestructible(false);
                        found = true;
                    }
                    if(!found&&((String)level.getElement(i, j)).compareTo("CleanTerrein")==0){
                        b.setElement(new Terrain());
                        b.getElement().setId(Element.CleanTerrainId);
                        b.getElement().setPriority(Element.CleanTerrainPriority);
                        ((Terrain)b.getElement()).setAsCleanTerrain();
                        found = true;
                    }
                    if(!found&&((String)level.getElement(i, j)).compareTo("DirtyTerrein")==0){
                        b.setElement(new Terrain());
                        b.getElement().setId(Element.DirtyTerrainId);
                        b.getElement().setPriority(Element.DirtyTerrainPriority);
                        found = true;
                    }
                    if(!found&&((String)level.getElement(i, j)).compareTo("Weight")==0){
                        b.setElement(new Weight());
                        b.getElement().setId(Element.WeightId);
                        b.getElement().setPriority(Element.WeightPriority);
                        found = true;
                    }
                    if(!found&&((String)level.getElement(i, j)).compareTo("Beer")==0){
                        b.setElement(new Beer());
                        b.getElement().setId(Element.BeerId);
                        b.getElement().setPriority(Element.BeerPriority);
                        found = true;
                        this.remainingBeers++;
                    }
                    if(!found&&((String)level.getElement(i, j)).compareTo("Exit")==0){
                        b.setElement(new Exit());
                        b.getElement().setId(Element.ExitId);
                        b.getElement().setPriority(Element.ExitPriority);
                        found = true;
                        xExit = i;
                        yExit = j;
                    }
                    //the rest of elements must be completed in similar way
                    b.getElement().setBox(b);
                    boxes.addBox(b);
                    found = false;
                    updatedBoxes = new Vector();
                }
                
            }
        }
        
        /**
         * 
         * @return the instance game.
         */
        public Game getGame(){
            return game;
        }
        
        /**
         * Sets the game.
         */
        public void setGame(Game game){
            this.game = game;
        }

        /**
         * 
         * @return the instance hero.
         */
        public Hero getHero(){
            return hero;
        }
        
        /**
         * Sets the hero.
         */
        public void setHero(Hero hero){
            this.hero = hero;
        }

        
        /**
         * 
         * @return time that the player has to pass the level.
         */
	public int getRemainingTime() {
            if(this.timer.isRunning())
                return this.timer.getDuration()-this.timer.getElapsed();
            else
                return 0;
	}
	
        /**
         * Sets the remainingTime to the default value for starting again the level.
         * @param remainingTime
         */
	public void initializeRemainingTime(int remainingTime) {
            timer.setHandler(this);
            timer.setDuration(remainingTime);
            //the interval established by the author is 2 seconds
            timer.setInterval(2000);
            this.remainingTime = remainingTime;
	}
	
        /**
         * Starts the count down for the remainingTime.
         */
	public void startClock(){
            timer.start();
	}
	
        /**
         * Update the elements of the board than can be moved automatically, this
         * is the priority 2 elements.
         */
	public void updateBoard() {
            //save the current lifes, if the hero die during the updating, it will be stopped
            int lifes = this.getGame().getCurrentLifes();
            boolean heroAlive = true;
            for(int j=1;(heroAlive)&&(j<=this.getGame().getLevelsInfo().getLevel(this.game.getCurrentLevel()).getYDimension());j++){
                for(int i=1;(heroAlive)&&(i<=this.getGame().getLevelsInfo().getLevel(this.game.getCurrentLevel()).getXDimension());i++){
                    //if the box is not in the updated and it is priority 2 element
                    //(it is not possible to move then must be updated
                    if((!updatedBoxes.contains(this.boxes.getBox(i,j)))&&(this.boxes.getBox(i,j).getElement().getPriority()==2)){
                        //save the element id
                        char id = this.boxes.getBox(i,j).getElement().getId();
                        //move the given element
                        switch(id){
                            case(Element.AmoebaId):
                                ((Amoeba)this.boxes.getBox(i,j).getElement()).move();
                                break;
                            case(Element.BeerId):
                                ((Beer)this.boxes.getBox(i,j).getElement()).move(hero);
                                break;
                            case(Element.ButterFlyId):
                                ((Butterfly)this.boxes.getBox(i,j).getElement()).move();
                                break;
                            case(Element.ExpandingWallId):
                                ((ExpandingWall)this.boxes.getBox(i,j).getElement()).move();
                                break;
                            case(Element.FireFlyId):
                                ((Firefly)this.boxes.getBox(i,j).getElement()).move();
                                break;
                            case(Element.MagicWallId):
                                ((MagicWall)this.boxes.getBox(i,j).getElement()).move();
                                break;
                            case(Element.WeightId):
                                ((Weight)this.boxes.getBox(i,j).getElement()).move(hero);
                                break;
                        }
                        //exits the updating and stops the clock
                        if(this.getGame().getCurrentLifes()!=lifes){
                            timer.stop();
                            heroAlive = false;
                        }
                    }
                }
            }
            this.rebootUpdatedBoxes();
	}
	
        /**
         * 
         * @return The help of the level. 
         */
	public String getHelp() {
		return help;
	}
	
        /**
         * Establish the help of the level.
         */
	public void setHelp(String help) {
            this.help = help;
	}
	
        /**
         * 
         * @return all the boxes of the guard.
         */
	public CollectionOfBoxes getBoxes() {
		return boxes;
	}
        
        /**
         * 
         * @return the actual number of beers in the board.
         */
        public int getRemaningBeers(){
            return this.remainingBeers;
        }
        
        /**
         * Remove 1 beer to the remainingBeers
         */
        public void removeABeer(){
            this.remainingBeers = this.remainingBeers-1;
        }
        
        /**
         * Do visible the door of the exit.
         */
        public void openExitDoor(){
            ((Exit)this.getBoxes().getBox(xExit, yExit).getElement()).setVisible(true);
        }
        
        /**
         * 
         * @return the updatedBoxes vector
         */
        public Vector getUpdatedBoxes(){
            return this.updatedBoxes;
        }
        
        public void rebootUpdatedBoxes(){
            this.updatedBoxes = new Vector();
        }
        
        /**
         * Indicates that the timer has been started.
         * @param timer
         */
        public void timerStarted(Timer timer) {
            
        }

        /**
         * Indicates the time has finished.
         * @param timer
         */
        public void timerStopped(Timer timer) {
        }

        /**
         * Indicates that the timer has dead.
         * @param timer
         */
        public void timerDeath(Timer timer) {
            this.getGame().subtractALife();
        }

        /**
         * Indicates that the established interval was passed.
         * @param timer
         */
        public void timerInterval(Timer timer) {
            this.updateBoard();
            this.getGame().drawBoard();
        }
}
 
